package org.rency.crawler.fetch.service.url.impl;

import com.google.common.net.InternetDomainName;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.util.List;
import java.util.regex.Matcher;
import javax.annotation.Resource;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.rency.crawler.common.CrawlerConstants;
import org.rency.crawler.fetch.repository.MetaResourceRepository;
import org.rency.crawler.fetch.service.url.URLService;
import org.rency.crawler.plugins.service.UrlDetectorPlugin;
import org.rency.crawler.plugins.url.NormalizeUrl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public abstract class AbstractUrlService implements URLService,CrawlerConstants {

	private static final Logger logger = LoggerFactory.getLogger(AbstractUrlService.class);

	@Resource
	private UrlDetectorPlugin           urlDetectorPlugin;

	@Resource
	protected MetaResourceRepository    metaResourceRepository;

	@Override
	public boolean intoLeaf(NormalizeUrl normalizeUrl, int depth) {
		if(depth <= 0){
			return true;
		}
		String[] sections = StringUtils.split(normalizeUrl.getPath(),URI_PATH_SEPARATOR);
		return sections.length <= depth;
	}

	@Override
	public boolean sameDomain(NormalizeUrl normalizeUrl, String targetDomain) {
		if(normalizeUrl == null){
			return false;
		}
		if(targetDomain.endsWith("/")){
			targetDomain = StringUtils.substring(targetDomain,0,targetDomain.length() - 1);
		}
		String tempTargetDomain = targetDomain;
		String host = normalizeUrl.getHost();
		Matcher uriMatcher = PATTERN_PROTOCOL_PREFIX.matcher(host);
		if(uriMatcher.find()){
			host = uriMatcher.replaceFirst("");
		}

		Matcher domainMatcher = PATTERN_PROTOCOL_PREFIX.matcher(targetDomain);
		if(domainMatcher.find()){
			targetDomain = domainMatcher.replaceFirst("");
		}

		if(!host.startsWith(targetDomain)){
			return this.getTopDomain(normalizeUrl.getNormalizeUri()).startsWith(this.getTopDomain(tempTargetDomain));
		}
		return true;
	}

	@Override
	public NormalizeUrl normalize(String uri) {
		logger.debug("序列化URL地址:{}",uri);
		if(StringUtils.isBlank(uri)){
			return null;
		}

		List<String> excludePrefix = metaResourceRepository.getFetchExcludeUriPrefix();
		if(CollectionUtils.isNotEmpty(excludePrefix)){
			for(String prefix : excludePrefix){
				if(uri.toLowerCase().startsWith(prefix.toLowerCase())){
					return null;
				}
			}
		}

		NormalizeUrl normalizeUrl = urlDetectorPlugin.normalize(uri);
		if(normalizeUrl == null){
			return null;
		}

		List<String> excludeSuffix = metaResourceRepository.getFetchExcludeUriSuffix();
		if(CollectionUtils.isNotEmpty(excludeSuffix)){
			for(String suffix : excludeSuffix){
				if(normalizeUrl.getHost().toLowerCase().endsWith(suffix.toLowerCase())){
					return null;
				}
			}
		}

		uri = this.convertCharset(uri);
		if(StringUtils.isBlank(uri)){
			return null;
		}

		normalizeUrl = this.customRule(normalizeUrl);
		if(normalizeUrl == null){
			return null;
		}
		return normalizeUrl;
	}

	@Override
	public String getTopDomain(String uri) {
		try {
			URL url = new URL(uri);
			String host = url.getHost();
			InternetDomainName domainName = InternetDomainName.from(host);
			return domainName.topPrivateDomain().toString();
		}catch (Exception e){
			logger.warn("解析URI域名异常",e);
			return uri;
		}
	}

	/**
	 * 判断是否为乱码
	 * 如果是乱码则转换编码格式
	 * 不能转换则返回<p>null</p>
	 * </br>Created on 2016年6月30日
	 * @param url
	 * @return
	 */
	private String convertCharset(String url){
		if(StringUtils.isBlank(url)){
			return null;
		}
		if(!java.nio.charset.Charset.forName("UTF-8").newEncoder().canEncode(url)){
			try {
				return new String(url.getBytes("ISO-8859-1"),"UTF-8");
			} catch (UnsupportedEncodingException e) {
				logger.warn("判断乱码转码异常:[{}].",url,e.getMessage());
				return null;
			}
		}
		return url;
	}
	
	/**
	 * 定制URL过滤规则检测
	 * </br>Created on 2016年6月13日
	 * @param normalizeUrl
	 * @return
	 */
	protected abstract NormalizeUrl customRule(NormalizeUrl normalizeUrl);
}
